/*  JEVEMon, A Java-based EVEMon clone.
Copyright (C) 2011, Raul Ruiz

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package jeveme.datacontainers;

import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import jeveme.JEVEMeApp;
import org.jdesktop.application.ResourceMap;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author Raul Ruiz
 */
public class EVEMasterSkillSheet {
    
    private static EVEMasterSkillSheet instance;
    private static Document m_skillTreeDoc;
    private static EVESkillSheet m_skillSheet;
    
    private EVEMasterSkillSheet() {
        ResourceMap resourceMap = JEVEMeApp.getApplication().getMainView().getResourceMap();
        //Load the SkillTree.xml resource into memory for easy use throughout the program.
        try {
            InputStream is = getClass().getResourceAsStream("/jeveme/resources/eve/SkillTree.xml");            
            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            m_skillTreeDoc = builder.parse(is);
            m_skillSheet = new EVESkillSheet();
            parseSkillTreeDoc();
        }
        catch (Exception e) {System.out.println("Error loading SkillTre.xml: " + e.getMessage());}
    }
    
    public static synchronized EVEMasterSkillSheet getInstance() {
        if (instance == null) {
            instance = new EVEMasterSkillSheet();
        }
	return instance;
    }
    
    public ArrayList<EVESkillGroup> getSkillGroups() {
        
        ArrayList<EVESkillGroup> esg = new ArrayList<EVESkillGroup>();
        
        ArrayList<SkillGroup> sg = m_skillSheet.getSkillGroups();
        EVESkillGroup temp = null;
        for(int i=0;i<sg.size();i++) {
            SkillGroup s = sg.get(i);
            temp = new EVESkillGroup();
            temp.setSkillGroupID(s.getGroupID());
            temp.setSkillGroupName(s.getGroupName());
            
            esg.add(temp);
        }
        
        return esg;
    }
    
    public EVESkill getEVESkillByID(String ID) {
        EVESkill es = new EVESkill();
        Skill s = m_skillSheet.getSkillByID(ID);
        if(s.getTypeName() == null) {
            return null;
        }
        
        es.setTypeID(s.getTypeID());
        es.setGroupID(s.getGroupID());
        es.setName(s.getTypeName());
        es.setDescription(s.getDescription());
        es.setRank(s.getRank());
        
        return es;
    }
    
    public EVESkill getEVESkillByName(String name) {
        EVESkill es = new EVESkill();
        Skill s = m_skillSheet.getSkillByName(name);
        if(s.getTypeName() == null) {
            return null;
        }
        
        es.setTypeID(s.getTypeID());
        es.setGroupID(s.getGroupID());
        es.setName(s.getTypeName());
        es.setDescription(s.getDescription());
        es.setRank(s.getRank());
        
        return es;
    }
    
    /**
     * Parse the XML into our EVESkillSheet object.
     */
    private void parseSkillTreeDoc() {
        final String skillGroups = "//eveapi/result/rowset/row[@groupID]";
        System.out.println("Entered Parse Skill Tree");
        XPath xpath = XPathFactory.newInstance().newXPath();
        
        try {
                XPathExpression expr = xpath.compile(skillGroups);
                Object expr_result = expr.evaluate(m_skillTreeDoc, XPathConstants.NODESET);
                NodeList nodes = (NodeList) expr_result;
                
                for(int i=0; i < nodes.getLength(); i++) {
                    Node n = nodes.item(i);
                    //Get the groupId and groupName.
                    String groupID = n.getAttributes().getNamedItem("groupID").getNodeValue();
                    String groupName = n.getAttributes().getNamedItem("groupName").getNodeValue();
                    SkillGroup sg = new SkillGroup();
                    sg.setGroupID(groupID);
                    sg.setGroupName(groupName);

                    System.out.println("Seen node " + i + ". " + groupName);
                    
                    //Process all the skills in that group. Child nodes.
                    String skillsInGroup = "//eveapi/result/rowset/row[@groupID=" + groupID + "]/rowset/row";
                    XPath xpath2 = XPathFactory.newInstance().newXPath();
                    XPathExpression expr2 = xpath.compile(skillsInGroup);
                    Object expr_result2 = expr2.evaluate(m_skillTreeDoc, XPathConstants.NODESET);
                    NodeList skillsNodes = (NodeList) expr_result2;
                    for(int j=0; j<skillsNodes.getLength(); j++) {
                        Skill s = new Skill();
                        
                        Node skill = skillsNodes.item(j);
                        NodeList skillDetails = skillsNodes.item(j).getChildNodes();
                        
                        s.setGroupID(groupID);
                        s.setTypeID(skill.getAttributes().getNamedItem("typeID").getNodeValue());
                        s.setTypeName(skill.getAttributes().getNamedItem("typeName").getNodeValue());
                        s.setPublished(skill.getAttributes().getNamedItem("published").getNodeValue());
                        
                        for(int x=0; x<skillDetails.getLength(); x++) {
                            Node sdn = skillDetails.item(x);
                            NamedNodeMap sd_attributes = skillDetails.item(x).getAttributes();
                            //Description Node
                            if(sdn.getNodeName().equals("description")) {
                                s.setDescription(sdn.getTextContent());
                                continue;
                            }
                            //Rank Node
                            else if (sdn.getNodeName().equals("rank")) {
                                s.setRank(sdn.getTextContent());
                                continue;
                            }
                            //Rowset/Required Skills Node
                            else if(sdn.getNodeName().equals("rowset") && sd_attributes.getNamedItem("name").getNodeValue().equals("requiredSkills")) {
                                NodeList requiredSkills_nodes = sdn.getChildNodes();
                                for(int y=0; y<requiredSkills_nodes.getLength(); y++) {
                                    Node requiredSkill = requiredSkills_nodes.item(y);
                                    if(!requiredSkill.getNodeName().equals("row")) {
                                        continue;
                                    }
                                    NamedNodeMap requiredSkillMap = requiredSkill.getAttributes();
                                    String rs_typeID = requiredSkillMap.getNamedItem("typeID").getNodeValue();
                                    String rs_requiredLevel = requiredSkillMap.getNamedItem("skillLevel").getNodeValue();
                                    RequiredSkill rs = new RequiredSkill();
                                    rs.setSkillLevel(rs_requiredLevel);
                                    rs.setTypeID(rs_typeID);
                                    s.addRequiredSkill(rs);
                                    
                                }
                            }
                            
                            //Required Attributes
                            else if(sdn.getNodeName().equals("requiredAttributes")) {
                                NodeList attributes_nodes = sdn.getChildNodes();
                                for(int y=0; y<attributes_nodes.getLength(); y++) {
                                    Node attribute = attributes_nodes.item(y);
                                    if(attribute.getNodeName().equals("primaryAttribute")) {
                                        String attribute_text = attribute.getTextContent();
                                        if(attribute_text.equals("intelligence")) {
                                            s.setPrimaryAttribute(EVEAttribute.Intelligence);
                                            continue;
                                        }
                                        else if(attribute_text.equals("perception")) {
                                            s.setPrimaryAttribute(EVEAttribute.Perception);
                                            continue;
                                        }
                                        else if(attribute_text.equals("charisma")) {
                                            s.setPrimaryAttribute(EVEAttribute.Charisma);
                                            continue;
                                        }
                                        else if(attribute_text.equals("willpower")) {
                                            s.setPrimaryAttribute(EVEAttribute.Willpower);
                                            continue;
                                        }
                                        else if(attribute_text.equals("memory")) {
                                            s.setPrimaryAttribute(EVEAttribute.Memory);
                                            continue;
                                        }
                                    }
                                    else if(attribute.getNodeName().equals("secondaryAttribute")) {
                                        String attribute_text = attribute.getTextContent();
                                        if(attribute_text.equals("intelligence")) {
                                            s.setSecondaryAttribute(EVEAttribute.Intelligence);
                                            continue;
                                        }
                                        else if(attribute_text.equals("perception")) {
                                            s.setSecondaryAttribute(EVEAttribute.Perception);
                                            continue;
                                        }
                                        else if(attribute_text.equals("charisma")) {
                                            s.setSecondaryAttribute(EVEAttribute.Charisma);
                                            continue;
                                        }
                                        else if(attribute_text.equals("willpower")) {
                                            s.setSecondaryAttribute(EVEAttribute.Willpower);
                                            continue;
                                        }
                                        else if(attribute_text.equals("memory")) {
                                            s.setSecondaryAttribute(EVEAttribute.Memory);
                                            continue;
                                        }
                                    }
                                }
                            }
                            //Skill bonus collection
                            else if(sdn.getNodeName().equals("rowset") && sd_attributes.getNamedItem("name").getNodeValue().equals("skillBonusCollection")) {
                                
                            }
                        }
                        
                        //Debug Output
                        System.out.println("Skill Name: " + s.getTypeName());
                        System.out.println("Description: " + s.getDescription());
                        System.out.println("Rank: " + s.getRank());
                        System.out.println("Primary Attribute: " + s.getPrimaryAttribute());
                        System.out.println("Secondary Attribute: " + s.getSecondaryAttribute());
                        ArrayList<RequiredSkill> skillsNeeded = s.getRequiredSkills();
                        System.out.println("Required Skills: ");
                        for(int loop=0; loop < skillsNeeded.size(); loop++) {
                            System.out.println("\t" + skillsNeeded.get(loop).getTypeID() + " " + skillsNeeded.get(loop).getSkillLevel());
                        }
                        
                        
                        sg.addSkill(s);
                        
                    }
                    
                    
                    //Add the skill group.
                    m_skillSheet.addSkillGroup(sg);
                }
                
            }
            catch(Exception e) {}
    }
    
    @Override
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
    
    class EVESkillSheet {
        
        ArrayList<SkillGroup> m_skillGroups;
        
        public EVESkillSheet() {
            m_skillGroups = new ArrayList<SkillGroup>();
        }
        
        public ArrayList<SkillGroup> getSkillGroups() {
            return m_skillGroups;
        }
               
        public void addSkillGroup(SkillGroup sg) {
            m_skillGroups.add(sg);
        }
       
        public Skill getSkillByID(String ID) {
            Skill s = new Skill();
            Skill temp;
            
            for(int i=0; i<m_skillGroups.size(); i++) {
                temp = m_skillGroups.get(i).getSkillByID(ID);
                if(temp.getTypeID() == null) {
                    continue;
                }
                else {
                    s = temp;
                }
            }
            
            return s;
        }
        
        public Skill getSkillByName(String name) {
            Skill s = new Skill();
            
            Skill temp;
            
            for(int i=0; i<m_skillGroups.size(); i++) {
                temp = m_skillGroups.get(i).getSkillByName(name);
                if(temp.getTypeName() == null) {
                    continue;
                }
                else {
                    s = temp;
                }
            }
            
            return s;
        }
    }
    
    class SkillGroup {
        
        private String m_groupID;
        private String m_groupName;
        
        ArrayList<Skill> m_skills;
        
        public SkillGroup() {
            m_skills = new ArrayList<Skill>();
        }
        
        public void setGroupID(String groupID) {
            m_groupID = groupID;
        }
        
        public String getGroupID() {
            return m_groupID;
        }
        
        public void setGroupName(String groupName) {
            m_groupName = groupName;
        }
        
        public String getGroupName() {
            return m_groupName;
        }
        
        public void addSkill(Skill s) {
            m_skills.add(s);
        }
        
        public Skill getSkillByID(String ID) {
            Skill s = new Skill();
            
            for(int i=0; i<m_skills.size(); i++) {
                if(m_skills.get(i).getTypeID().equals(ID)) {
                    s = m_skills.get(i);
                }
            }
            
            return s;
        }
        
        public Skill getSkillByName(String name) {
            Skill s = new Skill();
            
            for(int i=0; i<m_skills.size(); i++) {
                if(m_skills.get(i).getTypeName().equals(name)) {
                    s = m_skills.get(i);
                }
            }
            
            return s;
        }
        
        
    }
    
    class Skill {
        
        private String m_groupID;
        private String m_published;
        private String m_typeID;
        private String m_typeName;
        private String m_description;
        private String m_rank;
        
        private EVEAttribute m_primaryAttribute;
        private EVEAttribute m_secondaryAttribute;
        
        private ArrayList<RequiredSkill> m_requiredSkills;
        
        private ArrayList<BonusCollection> m_bonusCollection;
        
        public Skill() {
            m_requiredSkills = new ArrayList<RequiredSkill>();
            m_bonusCollection = new ArrayList<BonusCollection>();
        }
        
        public void setGroupID(String groupID) {
            m_groupID = groupID;
        }
        
        public String getGroupID() {
            return m_groupID;
        }
        
        public void setTypeID(String typeID) {
            m_typeID = typeID;
        }
        
        public String getTypeID() {
            return m_typeID;
        }
        
        public void setTypeName(String typeName) {
            m_typeName = typeName;
        }
        
        public String getTypeName() {
            return m_typeName;
        }
        
        public void setPublished(String published) {
            m_published = published;
        }
        
        public String getPublished() {
            return m_published;
        }
        
        public void setDescription(String description) {
            m_description = description;
        }
        
        public String getDescription() {
            return m_description;
        }
        
        public void setRank(String rank) {
            m_rank = rank;
        }
        
        public String getRank() {
            return m_rank;
        }
        
        public void setPrimaryAttribute(EVEAttribute primaryAttribute) {
            m_primaryAttribute = primaryAttribute;
        }
        
        public EVEAttribute getPrimaryAttribute() {
            return m_primaryAttribute;
        }
        
        public void setSecondaryAttribute(EVEAttribute secondaryAttribute) {
            m_secondaryAttribute = secondaryAttribute;
        }
        
        public EVEAttribute getSecondaryAttribute() {
            return m_secondaryAttribute;
        }
        
        public void addRequiredSkill(RequiredSkill rs) {
            m_requiredSkills.add(rs);
        }
        
        public ArrayList<RequiredSkill> getRequiredSkills() {
            return m_requiredSkills;
        }
    }
    
    class RequiredSkill {
        private String m_typeID;
        private String m_skillLevel;
        
        public RequiredSkill() {
            
        }
        
        public void setTypeID(String typeID) {
            m_typeID = typeID;
        }
        
        public String getTypeID() {
            return m_typeID;
        }
        
        public void setSkillLevel(String skillLevel) {
            m_skillLevel = skillLevel;
        }
        
        public String getSkillLevel() {
            return m_skillLevel;
        }
    }
    
    class BonusCollection {
        private String m_bonusType;
        private String m_bonusValue;
        
        public BonusCollection() {
            
        }
        
        public void setBonusType(String bonusType) {
            m_bonusType = bonusType;
        }
        
        public String getBonusType() {
            return m_bonusType;
        }
        
        public void setBonusValue(String bonusValue) {
            m_bonusValue = bonusValue;
        }
        
        public String getBonusValue() {
            return m_bonusValue;
        }
    }
    
}
